// 版权归Go作者所有。版权所有。
// 此源代码的使用受BSD样式
// 许可证的约束，该许可证可以在许可证文件中找到。

// 包maphash提供字节序列的哈希函数。
// 这些哈希函数用于实现哈希表或
// 其他需要将任意字符串或字节
// 序列映射到无符号64位整数的统一分布的数据结构。
// 哈希表或数据结构的每个不同实例都应该使用自己的种子。
// 
// 哈希函数在加密方面不安全。
// （加密使用请参见crypto/sha256和crypto/sha512）。
// 
package maphash

import (
	"internal/unsafeheader"
	"unsafe"
)

// 种子是一个随机值，用于选择由哈希计算的特定哈希函数
// 。如果两个散列使用相同的种子，它们将为任何给定的输入计算相同的散列值。
// 如果两个哈希使用不同的种子，它们很可能会为任何给定输入计算不同的哈希值。
// 
// 必须通过调用MakeSeed初始化种子。
// 零种子未初始化，不能与哈希的SetSeed方法一起使用。
// 
// 每个种子值都是单个进程的本地值，不能序列化
// 或在其他进程中重新创建。
type Seed struct {
	s uint64
}

// 散列计算字节序列的种子散列。
// 
// 零哈希是一个可用的有效哈希。
// 零散列在对重置、写入、种子或Sum64方法的第一次调用期间为自己选择一个随机种子。
// 要控制种子，请使用固定种子。
// 
// 计算的哈希值仅取决于初始种子和
// 提供给哈希对象的字节序列，而不取决于提供字节的方式
// 。例如，三个序列
// 
// h.Write（[]字节{f'，o'，o'}）
// h.WriteByte（'f'）；h、 写字节（'o'）；h、 WriteByte（'o'）
// h.writeestring（'foo'）
// 
// 都具有相同的效果。
// 
// 即使在对手控制被散列的字节序列的情况下，散列也是为了防止冲突。
// 
// 哈希对于多个goroutine并发使用是不安全的，但种子是安全的。
// 如果多个goroutine必须计算相同的种子哈希，
// 每个goroutine都可以声明自己的哈希，并使用公共种子调用SetSeed。
type Hash struct {
	_     [0]func()     // 不可比较
	seed  Seed          // 用于此哈希的初始种子
	state Seed          // 所有刷新字节的当前哈希
	buf   [bufSize]byte // 未刷新字节缓冲区
	n     int           // 未刷新字节数
}

// bufSize是哈希写入缓冲区的大小。
// 缓冲区确保写入仅取决于字节序列，
// 而不是WriteByte/Write/WriteString调用序列，
// 始终使用完整的缓冲区调用rthash（尾部除外）。
const bufSize = 128

// initSeed在必要时对哈希进行种子设定。
// initSeed在实际使用h.seed/h.state的任何操作之前被延迟调用。
// 请注意，在
// 只添加到h.buf的情况下，这不包括Write/WriteByte/WriteString。（如果他们写得太多，他们会调用h.flush，
// 这会调用h.initSeed。）
func (h *Hash) initSeed() {
	if h.seed.s == 0 {
		seed := MakeSeed()
		h.seed = seed
		h.state = seed
	}
}

// WriteByte将b添加到由h散列的字节序列中。
// 它从不失败；错误结果是用于实现io.ByteWriter。
func (h *Hash) WriteByte(b byte) error {
	if h.n == len(h.buf) {
		h.flush()
	}
	h.buf[h.n] = b
	h.n++
	return nil
}

// Write将b添加到由h散列的字节序列中。
// 它总是写所有的b，而且从不失败；计数和错误结果用于实现io.Writer。
func (h *Hash) Write(b []byte) (int, error) {
	size := len(b)
	// 处理h.buf中剩余的字节。
	// h.n<=bufSize始终为真。
	// 检查它是否免费，它让编译器消除边界检查。
	if h.n > 0 && h.n <= bufSize {
		k := copy(h.buf[h.n:], b)
		h.n += k
		if h.n < bufSize {
			// 将整个b复制到h.buf。
			return size, nil
		}
		b = b[k:]
		h.flush()
		// 此处不需要设置h.n=0；它发生在出口前。
	}
	// 处理尽可能多的完整缓冲区，无需复制，并且只调用initSeed一次。
	if len(b) > bufSize {
		h.initSeed()
		for len(b) > bufSize {
			h.state.s = rthash(&b[0], bufSize, h.state.s)
			b = b[bufSize:]
		}
	}
	// 复制尾部。
	copy(h.buf[:], b)
	h.n = len(b)
	return size, nil
}

// WriteString将s的字节添加到由h散列的字节序列中。
// 它总是写所有的s，从不失败；计数和错误结果用于实现io.StringWriter。
func (h *Hash) WriteString(s string) (int, error) {
	// WriteString镜像写入。请参阅“编写”以获取评论。
	size := len(s)
	if h.n > 0 && h.n <= bufSize {
		k := copy(h.buf[h.n:], s)
		h.n += k
		if h.n < bufSize {
			return size, nil
		}
		s = s[k:]
		h.flush()
	}
	if len(s) > bufSize {
		h.initSeed()
		for len(s) > bufSize {
			ptr := (*byte)((*unsafeheader.String)(unsafe.Pointer(&s)).Data)
			h.state.s = rthash(ptr, bufSize, h.state.s)
			s = s[bufSize:]
		}
	}
	copy(h.buf[:], s)
	h.n = len(s)
	return size, nil
}

// Seed返回h的Seed值。
func (h *Hash) Seed() Seed {
	h.initSeed()
	return h.seed
}

// SetSeed将h设置为使用seed，它必须由MakeSeed 
// 或另一个散列的seed方法返回。
// 具有相同种子的两个哈希对象的行为相同。
// 两个具有不同种子的哈希对象的行为很可能不同。
// 在此调用之前添加到h的任何字节都将被丢弃。
func (h *Hash) SetSeed(seed Seed) {
	if seed.s == 0 {
		panic("maphash: use of uninitialized Seed")
	}
	h.seed = seed
	h.state = seed
	h.n = 0
}

// 重置将丢弃添加到h的所有字节。
// （种子保持不变）
func (h *Hash) Reset() {
	h.initSeed()
	h.state = h.seed
	h.n = 0
}

// 前提条件：缓冲区已满。
func (h *Hash) flush() {
	if h.n != len(h.buf) {
		panic("maphash: flush of partially full buffer")
	}
	h.initSeed()
	h.state.s = rthash(&h.buf[0], h.n, h.state.s)
	h.n = 0
}

// Sum64返回h的当前64位值，该值取决于
// h的种子以及自
// 上次调用重置或设置种子后添加到h的字节序列。
// 
// Sum64结果的所有位都接近均匀分布，
// 独立分布，因此可以使用位掩蔽、移位或模运算安全地减少
// 。
func (h *Hash) Sum64() uint64 {
	h.initSeed()
	return rthash(&h.buf[0], h.n, h.state.s)
}

// MakeSeed返回一个新的随机种子。
func MakeSeed() Seed {
	var s1, s2 uint64
	for {
		s1 = uint64(runtime_fastrand())
		s2 = uint64(runtime_fastrand())
		// 我们使用seed 0表示未初始化的seed/散列，
		// 所以继续尝试，直到得到非零seed。
		if s1|s2 != 0 {
			break
		}
	}
	return Seed{s: s1<<32 + s2}
}

// go:linkname runtime_fastrand runtime.fastrand 
func runtime_fastrand() uint32

func rthash(ptr *byte, len int, seed uint64) uint64 {
	if len == 0 {
		return seed
	}
	// 运行时哈希程序仅在uintptr上工作。对于64位
	// 体系结构，我们直接使用哈希程序。否则，
	// 我们在低32位和高32位上使用两个并行哈希器。
	if unsafe.Sizeof(uintptr(0)) == 8 {
		return uint64(runtime_memhash(unsafe.Pointer(ptr), uintptr(seed), uintptr(len)))
	}
	lo := runtime_memhash(unsafe.Pointer(ptr), uintptr(seed), uintptr(len))
	hi := runtime_memhash(unsafe.Pointer(ptr), uintptr(seed>>32), uintptr(len))
	return uint64(hi)<<32 | uint64(lo)
}

// go:linkname runtime\u memhash runtime.memhash 
// go:noescape 
func runtime_memhash(p unsafe.Pointer, seed, s uintptr) uintptr

// Sum将哈希的当前64位值追加到b。
// 它是为实现hash.hash而存在的。
// 对于直接调用，使用Sum64更有效。
func (h *Hash) Sum(b []byte) []byte {
	x := h.Sum64()
	return append(b,
		byte(x>>0),
		byte(x>>8),
		byte(x>>16),
		byte(x>>24),
		byte(x>>32),
		byte(x>>40),
		byte(x>>48),
		byte(x>>56))
}

// Size返回h的哈希值大小，8字节。
func (h *Hash) Size() int { return 8 }

// BlockSize返回h的块大小。
func (h *Hash) BlockSize() int { return len(h.buf) }
